﻿#include "Toast.h"
#include "ui_Toast.h"

#include <QApplication>
#include <QDesktopWidget>
#include <QStyle>
#include <QScreen>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QGraphicsDropShadowEffect>
#include <QDebug>

QWidget* Toast::toastParent = nullptr;
QMap<Qt::Alignment, QList<QPointer<Toast>>> Toast::activeToasts;

Toast::Toast(const QString& msg, const QIcon& icon,
             const QColor& bgColor, int durationMs,
             Qt::Alignment position, QWidget* parent)
    : QWidget(parent)
    , ui(new Ui::Toast)
    , duration(durationMs)
    , align(position)
{
    ui->setupUi(this);

    setWindowFlags(Qt::FramelessWindowHint | Qt::ToolTip);
    setAttribute(Qt::WA_TranslucentBackground, true);

    // 阴影效果
    auto* shadow = new QGraphicsDropShadowEffect(this);
    shadow->setBlurRadius(15);
    shadow->setOffset(0, 0);
    shadow->setColor(QColor(0, 0, 0, 180));
    ui->widget->setGraphicsEffect(shadow);

    ui->iconLabel->setPixmap(icon.pixmap(ui->iconLabel->size()));
    ui->textLabel->setText(msg);

    ui->widget->setStyleSheet(QString("background: %1; border-radius: 8px; padding: 8px 16px;").arg(bgColor.name()));

    // 定时关闭
    timer = new QTimer(this);
    connect(timer, &QTimer::timeout, this, &Toast::fadeOut);

    // 动画
    opacityAnim = new QPropertyAnimation(this, "windowOpacity", this);
    opacityAnim->setDuration(500);
    opacityAnim->setStartValue(1.0);
    opacityAnim->setEndValue(0.0);

    moveAnim = new QPropertyAnimation(this, "pos", this);
    moveAnim->setDuration(500);

    animationGroup = new QParallelAnimationGroup(this);
    animationGroup->addAnimation(opacityAnim);
    animationGroup->addAnimation(moveAnim);
    connect(animationGroup, &QParallelAnimationGroup::finished, this, [=](){
        close();
        deleteLater();
    });

    resize(sizeHint());
    timer->start(duration);
}

Toast::~Toast()
{
    delete ui;
}

void Toast::setToastParent(QWidget* parent)
{
    toastParent = parent;
}

void Toast::showEvent(QShowEvent* event)
{
    QWidget::showEvent(event);

    // QWidget* base = toastParent ? toastParent : QApplication::activeWindow();
    // if (!base) base = QApplication::desktop();

    // QRect rect = base->rect();
    // if (auto* widget = qobject_cast<QWidget*>(base)) {
    //     rect = widget->rect();
    //     rect.moveTopLeft(widget->mapToGlobal(QPoint(0,0)));
    // } else if (auto* screen = qobject_cast<QScreen*>(base)) {
    //     rect = screen->geometry();
    // }

    // 加入堆叠队列
    activeToasts[align].append(this);
    repositionToasts();
}

void Toast::fadeOut()
{
    timer->stop();

    // 出场动画
    QPoint endPos = pos();
    if (align & Qt::AlignBottom)
        endPos.setY(endPos.y() + 30);
    else
        endPos.setY(endPos.y() - 30);

    moveAnim->setStartValue(pos());
    moveAnim->setEndValue(endPos);

    opacityAnim->setStartValue(1.0);
    opacityAnim->setEndValue(0.0);

    animationGroup->start();

    activeToasts[align].removeAll(this);
    repositionToasts();
}

void Toast::repositionToasts()
{
    QWidget* base = toastParent ? toastParent : QApplication::activeWindow();
    if (!base) base = QApplication::desktop();

    QRect rect = base->rect();
    if (auto* widget = qobject_cast<QWidget*>(base)) {
        rect = widget->rect();
        rect.moveTopLeft(widget->mapToGlobal(QPoint(0,0)));
    } else if (auto* screen = qobject_cast<QScreen*>(base)) {
        rect = screen->geometry();
    }

    int margin = 20;
    int offset = 0;
    QList<QPointer<Toast>>& list = activeToasts[align];

    for (auto& toast : list) {
        if (!toast) continue;

        QPoint pos;
        if (align & Qt::AlignBottom)
            pos.setY(rect.bottom() - toast->height() - margin - offset);
        else if (align & Qt::AlignTop)
            pos.setY(rect.top() + margin + offset);
        else
            pos.setY(rect.center().y() - toast->height()/2 + offset);

        if (align & Qt::AlignRight)
            pos.setX(rect.right() - toast->width() - margin);
        else if (align & Qt::AlignLeft)
            pos.setX(rect.left() + margin);
        else
            pos.setX(rect.center().x() - toast->width()/2);

        toast->move(pos);

        offset += toast->height() + 10;
    }
}

// --------------------- 静态工厂方法 ---------------------

Toast* Toast::info(const QString& msg, int durationMs, Qt::Alignment position)
{
    QIcon icon = QApplication::style()->standardIcon(QStyle::SP_MessageBoxInformation);
    auto* t = new Toast(msg, icon, QColor("#2196F3"), durationMs, position, toastParent);
    t->show();
    return t;
}

Toast* Toast::warning(const QString& msg, int durationMs, Qt::Alignment position)
{
    QIcon icon = QApplication::style()->standardIcon(QStyle::SP_MessageBoxWarning);
    auto* t = new Toast(msg, icon, QColor("#FF9800"), durationMs, position, toastParent);
    t->show();
    return t;
}

Toast* Toast::error(const QString& msg, int durationMs, Qt::Alignment position)
{
    QIcon icon = QApplication::style()->standardIcon(QStyle::SP_MessageBoxCritical);
    auto* t = new Toast(msg, icon, QColor("#F44336"), durationMs, position, toastParent);
    t->show();
    return t;
}

Toast* Toast::success(const QString& msg, int durationMs, Qt::Alignment position)
{
    QIcon icon = QApplication::style()->standardIcon(QStyle::SP_DialogApplyButton);
    auto* t = new Toast(msg, icon, QColor("#4CAF50"), durationMs, position, toastParent);
    t->show();
    return t;
}
